// 封装小程序的wx.request和upload
class WxRequest {
  // 定义一个实例属性,设置默认请求参数
  defaults = {
    baseUrl: '',//请求基础地址
    url: '', // 接口的请求路径
    data: null, // 请求参数
    method: 'GET', //默认请求方法
    // 请求头
    header: {
      "Content-type": "application/json", // 设置数据的交互格式
    },
    timeout: 60000, // 默认超时时长 
    isLoading: true //控制是否使用默认loading true表示使用
  }

  // 定义拦截器对象
  interceptors = {
    // 请求拦截器 数据发送之前,对数据进行修改
    // 这里不对数据进行处理
    request: (config) => config,
    response: (response) => response
  }

  // 定义初始数组队列 
  // 初始值是一个空数组,用来存储请求队列,存储请求标识
  queue = []

  // 用户创建和初始化类的属性和方法
  // 在实例化时传入的参数,会被constructor形参接收
  constructor(params = {}) {
    // 合并请求参数,覆盖默认参数
    this.defaults = Object.assign({}, this.defaults, params)
  }

  // request实例方法接收一个对象类型的参数
  // 属性值和wx.request方法调用时传递的参数保持一致
  request(options) {
    // 如果有新的请求,就清除上一次的定时器
    this.timerId && clearTimeout(this.timerId)

    // 注意: 需要先合并完整请求地址
    if(!options.url.startsWith('https')) {
      options.url = this.defaults.baseUrl+options.url
    }

    // 合并请求参数
    options = { ...this.defaults, ...options }

    // loading显示 上传自带loading
    if(options.isLoading && options.method !== 'UPLOAD') {
      // 在请求发送之前,添加loading效果
      // 并发请求 后面的loading会覆盖前面的
      // 或是第一个请求好了 hideloading 后面请求还没完成
      // 返回过快,或一个请求在另一个请求后立即触发 造成loading闪烁
      // 判断queue是否为空,是空,说明没有请求正在进行, 当下这个请求, 就显示loading 不是就不显示
      this.queue.length === 0 && wx.showLoading()
      // 然后立即向queue中添加请求标识
      // 每个标识代表一个请求
      this.queue.push('request')
    }

    // 在请求发送之前,调用请求拦截器,新增或修改数据 函数内部返回新的config
    options = this.interceptors.request(options)

    // 需要使用promise 封装 wx.request,处理异步请求
    return new Promise((resolve, reject) => {
      if(options.method === 'UPLOAD') {
        wx.uploadFile({
          ...options,
          success: (res) => {
            // 将服务器数据进行转换
            res.data = JSON.parse(res.data)
            // console.log(res)
            //合并参数
            const mergeRes = Object.assign({}, res, { config:options, isSuccess: true})
            // console.log('mergeRes', mergeRes)
            // console.log('xxx', this.interceptors.response(mergeRes))
            resolve(this.interceptors.response(mergeRes))
          },
          fail: (error) => {
            const mergeRes = Object.assign({}, error, { config:options, isSuccess: false})
            reject(this.interceptors.response(mergeRes))
          }
        })
      } else {
        // wx.request
        wx.request({
         ...options,
         success: (res) => {
          //  console.log('wxrequest成功返回的res', res)
           // 不管成攻还是失败响应,都要调用响应拦截器
            // 响应拦截器接收服务器数据,对数据进行处理,处理好之后进行返回
            // 通过resolve将数据返回
  
            // 在响应拦截器传递参数时,需要将请求参数也  一起传递
            // 方便进行代码的调试或进行其他逻辑处理,需要先合并参数
            // 然后将合并的参数传递给响应拦截器
            // isSuccess: true 判断是fail 还是 success fail直接返回网络异常
            // console.log('res',res)
            // console.log('config', options)
            const mergeRes = Object.assign({}, res, {config: options, isSuccess: true})
            // console.log('整合之后成功返回的mergeRes', mergeRes)
            // 当接口调用成功时会触发
            resolve(this.interceptors.response(mergeRes))
         },
         fail: (err) => {
          const mergeRes = Object.assign({}, err, {config: options, isSuccess: false})
          // 当接口调用失败时会触发
          reject(this.interceptors.response(mergeRes))
         },
         complete: () =>{
           // 无论请求成功失败 都会执行
          if(options.isLoading) {
             // 请求结束后,每次从queue删除一个标识
             this.queue.pop()
             // 桥梁 每次对应请求结束后 再添加一个 保持queue中一直有标识 wx.loading就会一直存在
             // 如果后续没有请求 从定时器清除这个新添加的标识
             // 如果后续有请求 标识存在则不会清除 会直接进行下个请求的队列添加 
             // 一直到最后一个请求结束 再通过定时器最后的标识
             //用来处理Loading闪烁问题
             this.queue.length===0&&this.queue.push('request')
              // 毁桥指令
              this.timerId = setTimeout(()=>{
                this.queue.pop()
                // 删除后,判断queue是否为空,
                // 是空,说明并发请求完成
                // 就隐藏loading
                this.queue.length===0 && wx.hideLoading()
                clearTimeout(this.timerId)
              }, 1)
          }
         }
        })
      }
    })












  }
  // 封装其他简易请求
  get (url, data = {}, config = {}) {
    return this.request(Object.assign({ url, data, method: 'GET' }, config))
  }

  delete (url, data = {}, config = {}) {
    return this.request(Object.assign({ url, data, method: 'DELETE' }, config))
  }

  post (url, data = {}, config = {}) {
    return this.request(Object.assign({ url, data, method: 'Post' }, config))
  }

  put (url, data = {}, config = {}) {
    return this.request(Object.assign({ url, data, method: 'Put' }, config))
  }

  // 封装Promise.all 处理并发请求
  all (...promise) {
    // console.log('promise', promise)
    // 剩余参数: ...args args是一个数组
    return Promise.all(promise)
  }

  //封装upload
  upload (url, filePath, name = 'file', config = {}) {
    return this.request(Object.assign({url, filePath, name, method: 'UPLOAD'}, config))
  }
}


export default WxRequest















